﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Net;
using System.Text.RegularExpressions;
using System.Security.Principal;
using System.Globalization;
using HTMLLib.Entities;
using System.Diagnostics;

namespace HTMLLib
{
    public class Page
    {
        // Fields
        private string _baseUrl;
        private List<string> _urlFolders;
        private string _source;
        private string _title;
        private List<Hyperlink> _links;
        private long _loadingTime;

        /// <summary>
        /// Gets the Url that is being scanned.
        /// </summary>
        public string BaseUrl
        {
            get
            {
                return _baseUrl;
            }
            private set
            { 
                _baseUrl = value; 
            }
        }

        /// <summary>
        /// Gets a List of Folders used within the Url
        /// </summary>
        public List<string> UrlFolders 
        {
            get
            {
                return _urlFolders;
            }
            private set
            {
                _urlFolders = value;
            }
        }

        /// <summary>
        /// Gets the sourcecode of a webpage.
        /// </summary>
        public string Source 
        { 
            get
            {
                return _source;
            }
            private set
            {
                _source = value;
            }
        }

        /// <summary>
        /// Gets the title of a webpage
        /// </summary>
        public string Title
        {
            get
            {
                return _title;
            }
            private set
            {
                _title = value;
            }
        }

        /// <summary>
        /// Gets a list of all Hyperlinks used within the scanned website.
        /// </summary>
        public List<Hyperlink> Links
        {
            get
            {
                return _links;
            }
            private set
            {
                _links = value;
            }
        }

        /// <summary>
        /// Gets the loading time of a website.
        /// </summary>
        public long LoadingTime
        {
            get
            {
                return _loadingTime;
            }
            private set
            {
                _loadingTime = value;
            }
        }
        

        /// <summary>
        /// Construct an object of a webpage please!
        /// </summary>
        /// <param name="url">Url of the page you would like to scan.</param>
        public Page(string url)
        {
            Stopwatch w = new Stopwatch();
            w.Start();

            _baseUrl = url;
            _urlFolders = this.GetUrlFolders(url);
            _source = this.GetSource(url);
            _title = this.GetTitle(url);
            _links = this.GetAllLinks(url);

            w.Stop();

            _loadingTime = w.ElapsedMilliseconds;
        }

        private List<string> GetUrlFolders(string url)
        {
            url = url.Replace(@"http://", "");
            string[] tempFolders = url.Split('/');
            
            List<string> folders = new List<string>();
            for (int i = 1; i < tempFolders.Length; i++)
                folders.Add(tempFolders[i]);

            return folders;
        }

        private string GetSource(string url)
        {
            WebRequest request = WebRequest.Create(url);
            request.Proxy = WebRequest.DefaultWebProxy;
            request.Proxy.Credentials = CredentialCache.DefaultCredentials;
            
            WebResponse response = request.GetResponse();

            StreamReader sr = new StreamReader(response.GetResponseStream(), Encoding.UTF8);
            
            return sr.ReadToEnd();
        }

        private List<Hyperlink> GetAllLinks(string url)
        {
            if (_source == string.Empty)
                _source = this.GetSource(url);

            List<Hyperlink> links = new List<Hyperlink>();
            MatchCollection matches = Regex.Matches(_source, @"(<a.*?>.*?</a>)", RegexOptions.Singleline);

            foreach (Match match in matches)
            {
                string value = match.Groups[1].Value;
                Hyperlink link = new Hyperlink();

                Match href = Regex.Match(value, @"href=\""(.*?)\""", RegexOptions.Singleline);
                if (href.Success)
                    link.Href = href.Groups[1].Value;

                Match title = Regex.Match(value, @"title=\""(.*?)\""", RegexOptions.Singleline);
                if (title.Success)
                    link.Title = title.Groups[1].Value;

                Match target = Regex.Match(value, @"target=\""(.*?)\""", RegexOptions.Singleline);
                if (target.Success)
                    link.Target = target.Groups[1].Value;

                Match sClass = Regex.Match(value, @"class=\""(.*?)\""", RegexOptions.Singleline);
                if (sClass.Success)
                    link.Class = sClass.Groups[1].Value;

                Match id = Regex.Match(value, @"id=\""(.*?)\""", RegexOptions.Singleline);
                if (id.Success)
                    link.ID = id.Groups[1].Value;

                string t = Regex.Replace(value, @"\s*<.*?>\s*", "", RegexOptions.Singleline);
                link.Text = t;

                bool shouldAdd = 
                    link.Text != string.Empty && 
                    link.Href != string.Empty &&
                    !link.Href.StartsWith("#", true, CultureInfo.CurrentCulture) &&
                    !link.Href.StartsWith("java", true, CultureInfo.CurrentCulture);
                
                if (shouldAdd)
                    links.Add(link);
            }

            return links;
        }

        private string GetTitle(string url)
        {
            if (_source == string.Empty)
                _source = this.GetSource(url);

            return Regex.Match(_source, @"\<title\b[^>]*\>\s*(?<Title>[\s\S]*?)\</title\>", RegexOptions.IgnoreCase)
                          .Groups["Title"].Value;
        }

        public override string ToString()
        {
            return _source;
        }
    }
}
